﻿Imports System.Linq.Expressions
Imports System.Runtime.CompilerServices
Imports System.Reflection
Imports System.IO
Imports System.Runtime.Serialization.Formatters.Binary

'http://blogs.msdn.com/b/mattwar/archive/2007/07/30/linq-building-an-iqueryable-provider-part-i.aspx

Namespace Load

    ''' <summary>
    ''' クエリー
    ''' </summary>
    ''' <typeparam name="T"></typeparam>
    ''' <remarks></remarks>
    Public Class Query(Of T)
        Implements IQueryable(Of T)
        Implements IQueryable
        Implements IEnumerable(Of T)
        Implements IEnumerable
        Implements IOrderedQueryable(Of T)
        Implements IOrderedQueryable
        Implements IQuery
        Implements IQuery(Of T)
        Implements ICloneableExporter(Of T)

        ''' <summary>
        ''' モックを作成します。
        ''' </summary>
        ''' <returns></returns>
        ''' <remarks>モックは実行するとエラーになります。</remarks>
        Public Shared Function CreateMockUp() As Query(Of T)
            Return New Query(Of T)
        End Function

        Private Sub New()
        End Sub

        Public Sub New(provider As QueryProviderBase)
#If DEBUG Then
            If provider Is Nothing Then Throw New ArgumentNullException("provider")
#End If
            _provider = provider
            Me.Expression = Expression.Constant(Me)
        End Sub

        Public Sub New(provider As QueryProviderBase, expression As Expression)
#If DEBUG Then
            If provider Is Nothing Then Throw New ArgumentNullException("provider")
            If expression Is Nothing Then Throw New ArgumentNullException("expression")
            If Not GetType(IQueryable(Of T)).IsAssignableFrom(expression.Type) Then Throw New ArgumentOutOfRangeException("expression")
#End If
            _provider = provider
            Me.Expression = expression
        End Sub

        Private _provider As QueryProviderBase
        ''' <summary>
        ''' クエリープロバイダー
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Public Property Provider() As QueryProviderBase
            Get
                Return _provider
            End Get
            Friend Set(value As QueryProviderBase)
                _provider = value
            End Set
        End Property

        ''' <summary>
        ''' 式ツリー
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Property Expression As Expression Implements IQuery.Expression

        ''' <summary>
        ''' パラメータビルダーリスト
        ''' </summary>
        ''' <value></value>
        ''' <returns></returns>
        ''' <remarks></remarks>
        Friend Property Builders As New List(Of Action(Of Func(Of MemberInfo, String), System.Func(Of Object, String), System.Action(Of String))) Implements IQuery.ParameterBuilders

        ''' <summary>
        ''' パラメータを組み立てます
        ''' </summary>
        ''' <param name="nameReader">SQL列名取得関数</param>
        ''' <param name="prmRegister">パラメータ登録関数</param>
        ''' <param name="whereRegister">SQL条件文登録関数</param>
        ''' <remarks></remarks>
        Private Sub Build(nameReader As Func(Of MemberInfo, String), prmRegister As System.Func(Of Object, String), whereRegister As System.Action(Of String)) Implements IQuery.BuildParameter
            For Each item In Me.Builders
                item.Invoke(nameReader, prmRegister, whereRegister)
            Next
        End Sub

#Region "IQueryable"
        Private ReadOnly Property IQueryable_Expression() As Expression Implements IQueryable.Expression
            Get
                Return Me.Expression
            End Get
        End Property

        Private ReadOnly Property IQueryable_ElementType() As Type Implements IQueryable.ElementType
            Get
                Return GetType(T)
            End Get
        End Property

        Private ReadOnly Property IQueryable_Provider() As IQueryProvider Implements IQueryable.Provider
            Get
                Return Me.Provider
            End Get
        End Property
#End Region

#Region "IQuery"
        Public Property IQuery_Provider As QueryProviderBase Implements IQuery.Provider
            Get
                Return Me.Provider
            End Get
            Friend Set(value As QueryProviderBase)
                Me.Provider = value
            End Set
        End Property
#End Region

#Region "IEnumerable"
        Public Function GetEnumerator() As IEnumerator(Of T) Implements System.Collections.Generic.IEnumerable(Of T).GetEnumerator
            Return DirectCast(Me.Provider.Execute(Me.Expression), IEnumerable(Of T)).GetEnumerator()
        End Function

        Private Function IEnumerable_GetEnumerator() As IEnumerator Implements IEnumerable.GetEnumerator
            Return DirectCast(Me.Provider.Execute(Me.Expression), IEnumerable).GetEnumerator()
        End Function
#End Region

#Region "ICloneableExporter"
        Public Function Clone() As ICloneableExporter(Of T) Implements ICloneableExporter(Of T).Clone
            Return CloneableExporter.Clone(Me.ToList)
        End Function

        Private Function ToArray1() As T() Implements ICloneableExporter(Of T).ToArray
            Return Me.ToArray
        End Function

        Public Function ToItem() As T Implements ICloneableExporter(Of T).ToItem
            Dim lst = Me.ToList
            If lst.Count <> 1 Then Return Nothing
            Return lst.First
        End Function

        Private Function ToList1() As System.Collections.Generic.List(Of T) Implements ICloneableExporter(Of T).ToList
            Return Me.ToList
        End Function
#End Region

    End Class

End Namespace